package com.gitee.wsl.doc.prosemirror.ui.command

import com.gitee.wsl.doc.prosemirror.model.content.ResolvedPos
import com.gitee.wsl.doc.prosemirror.model.content.ext.findCutAfter
import com.gitee.wsl.doc.prosemirror.model.content.ext.findCutBefore
import com.gitee.wsl.doc.prosemirror.state.Command
import com.gitee.wsl.doc.prosemirror.state.CommandDispatch
import com.gitee.wsl.doc.prosemirror.state.EditorState
import com.gitee.wsl.doc.prosemirror.state.selection.NodeSelection
import com.gitee.wsl.doc.prosemirror.ui.EditorView
import com.gitee.wsl.doc.prosemirror.ui.ext.TextblockDir
import com.gitee.wsl.doc.prosemirror.ui.ext.endOfTextblock

/**
 * 当选择为空且位于文本块末尾时，尝试选择下一个节点
 * @param state 编辑器状态
 * @param dispatch 事务处理回调函数
 * @param view 编辑器视图（可选）
 * @return 操作是否成功执行
 */
object SelectNodeForward: UiCommand{
    override fun exec(
        view: EditorView?,
        state: EditorState,
        dispatch: CommandDispatch?,
    ): Boolean {
        val empty = state.selection.isEmpty
        val head = state.selection._head
        if (!empty) return false

        val cut = if (head.parent.isTextblock) {
            if (view != null && !view.endOfTextblock(state, TextblockDir.DirHorizontal.forward )) {
                return false
            }
            if (view == null && head.parentOffset < head.parent.content.size) {
                return false
            }
            head.findCutAfter()
        } else {
            null
        }

        val node = cut?.nodeAfter
        if (node == null || !NodeSelection.isSelectable(node)) {
            return false
        }

        if (dispatch != null) {
            dispatch(
                state.tr.setSelection(NodeSelection.create(state.doc, cut.pos)).scrollIntoView()
            )
        }
        return true
    }
}

val Command.Companion.selectNodeForward get() = SelectNodeForward

object SelectNodeBackward: UiCommand{
    override fun exec(
        view: EditorView?,
        state: EditorState,
        dispatch: CommandDispatch?,
    ): Boolean {
        val selection = state.selection
        val head = selection._head
        val empty = selection.isEmpty

        if (!empty) return false

        var cut: ResolvedPos? = head

        if (head.parent.isTextblock) {
            val atTextblockStart = if (view != null) {
                !view.endOfTextblock( state, TextblockDir.DirHorizontal.backward)
            } else {
                head.parentOffset > 0
            }
            if (atTextblockStart) return false

            cut = head.findCutBefore()
        }

        val node = cut?.nodeBefore
        if (node == null || !NodeSelection.isSelectable(node)) return false

        dispatch?.invoke(
            state.tr.setSelection(
                NodeSelection.create(state.doc, cut.pos - node.nodeSize)
            ).scrollIntoView()
        )
        return true
    }
}

val Command.Companion.selectNodeBackward
    get() = SelectNodeBackward